﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using TA.DotNetUtils;

public static class _StringExtensions
{
	#region INTERNAL
	#region VARS
	static string[] NounsWithoutPlural = new[] {
    "deer",
    "moose",
    "sheep",
    "bison",
    "salmon",
    "pike",
    "trout",
    "fish",
    "swine",
		"samurai",
		"data",
		"graffiti",
		"deceit", "information", "cunning",
		"honesty", "wisdom", "beauty", "intelligence", "stupidity", "curiosity", 
		"chemistry", "geometry", "surgery", "blues", "jazz", "impressionism", "surrealism",
	}, NounsWithoutSingular = new[] {
		"cattle", "billiards", "clothes", "measles", "thanks",
		"pants", "pliers", "scissors", "shorts", "tongs", "trousers", "glasses",
		"species", "series", "blues",
	};
	static Dictionary<string, string> IrregularPlural, IrregularSingular;
	static Regex rgxTag = new Regex(@"\<(/)?([\w:]+)(?:[^""'/>]*(?:(?:""[^""]*"")|(?:'[^']*')))*[^/>]*\>"),
		 rgxEndOfSentence = new Regex(@"(?<!Dr|Pres|Mr|Mrs|Ms|e\.g|etc)\.");
	#endregion
	#region INIT
	static _StringExtensions()
	{
		IrregularPlural = new Dictionary<string, string>();
		IrregularPlural["child"] = "children";
		IrregularPlural["foot"] = "feet";
		IrregularPlural["goose"] = "geese";
		IrregularPlural["louse"] = "lice";
		IrregularPlural["man"] = "men";
		IrregularPlural["mouse"] = "mice";
		IrregularPlural["tooth"] = "teeth";
		IrregularPlural["woman"] = "women";

		IrregularSingular = new Dictionary<string, string>();
		IrregularSingular["movies"] = "movie";
		IrregularSingular["children"] = "child";
		IrregularSingular["feet"] = "foot";
		IrregularSingular["geese"] = "goose";
		IrregularSingular["lice"] = "louse";
		IrregularSingular["men"] = "man";
		IrregularSingular["mice"] = "mouse";
		IrregularSingular["teeth"] = "tooth";
		IrregularSingular["women"] = "woman";
	}
	#endregion
	#endregion
	public static string StripTags(this string sThis)
	{
		StringBuilder sb = new StringBuilder();
		bool flag = true;

		foreach (char c in sThis)
		{
			if (c == '<') flag = false;
			else if (c == '>') flag = true;

			if (flag && c != '>') sb.Append(c);
		}
		return sb.ToString();
	}
	public static string Singularize(this string sThis)
	{
		string sLower = sThis.ToLower();
		if (sLower.EndsWith("ness")) return sThis;
		if (NounsWithoutSingular.Contains(sLower)) return sThis;
		if (IrregularSingular.ContainsKey(sLower)) return IrregularSingular[sLower];

		if (sThis.EndsWith("ies", StringComparison.CurrentCultureIgnoreCase))
			return sThis.Substring(0, sThis.Length - 3) + "y";
		if (sThis.EndsWith("es", StringComparison.CurrentCultureIgnoreCase))
			return sThis.Substring(0, sThis.Length - 2);
		if (sThis.EndsWith("s", StringComparison.CurrentCultureIgnoreCase))
			return sThis.Substring(0, sThis.Length - 1);
		return sThis;
	}
	public static string Pluralize(this string sThis)
	{
		string sLower = sThis.ToLower();
		if (sLower.EndsWith("ness")) return sThis;
		if (NounsWithoutPlural.Contains(sLower)) return sThis;
		if (IrregularPlural.ContainsKey(sLower)) return IrregularPlural[sLower];

		if (sThis.EndsWith("ies", StringComparison.CurrentCultureIgnoreCase))
			return sThis;
		if (sThis.EndsWith("ix", StringComparison.CurrentCultureIgnoreCase) ||
			sThis.EndsWith("ex", StringComparison.CurrentCultureIgnoreCase))
			return sThis.Substring(0, sThis.Length - 2) + "ices";
		if (sThis.EndsWith("is"))
			return sThis.Substring(0, sThis.Length - 2) + "es";

		char c = sThis[sThis.Length - 1];
		if (char.ToLower(c) == 'y')
		{
			if (char.IsUpper(c))
				return sThis.Substring(0, sThis.Length - 1) + "IES";
			else
				return sThis.Substring(0, sThis.Length - 1) + "ies";
		}
		if (c == 'h' || c == 's')
		{
			if (char.IsUpper(c))
				return sThis + "ES";
			else
				return sThis + "es";
		}
		if (char.IsUpper(c))
			return sThis + "S";
		else
			return sThis + "s";
	}
	public static string Capitalize(this string This)
	{
		if (This.Length == 0) return "";
		return This[0].ToString().ToUpper() + This.Substring(1).ToLower();
	}
	public static string TakeFirst(this string sThis, int min, int max, string appendix)
	{
		StringBuilder sb = new StringBuilder(),
			sbWord = new StringBuilder();
		for (var i = 0; i <= sThis.Length; ++i)
		{
			if (i == sThis.Length || Char.IsWhiteSpace(sThis[i]))
			{
				if (sbWord.Length > 0)
				{
					if (sb.Length + sbWord.Length <= max)
					{
						if (sb.Length > 0)
							sb.Append(" ");
						sb.Append(sbWord.ToString());
						sbWord.Length = 0;
					}
					else
					{
						if (sb.Length < min)
						{
							if (sb.Length > 0)
								sb.Append(" ");
							sb.Append(sbWord.ToString().Substring(0, max - sb.Length));
						}
						sb.Append(appendix);
						break;
					}
				}
			}
			else
			{
				sbWord.Append(sThis[i]);
			}
		}
		return sb.ToString();
	}
	public static string BreakByCaps(this string sThis)
	{
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < sThis.Length; ++i)
		{
			char c = sThis[i];

			if (char.IsUpper(c))
			{
				if (c == 'S' && i < sThis.Length - 3 && sThis[i + 1] == 'u' && sThis[i + 2] == 'b' && char.IsUpper(sThis[i + 3]))
				{
					i += 2;
					sb.Append("sub-");
				}
				else if (char.IsUpper(sThis[i + 1]))
				{
					sb.Append(c);
				}
				else
				{
					if (sb.Length > 0 && sb[sb.Length - 1] != '-') sb.Append(' ');
					sb.Append(char.ToLower(c));
				}
			}
			else
				sb.Append(c);
		}
		return sb.ToString();
	}
	public static string PrefixWithIndefArticle(this string sThis)
	{
		if (sThis[0].IsConsonant())
			return "a " + sThis;
		else
			return "an " + sThis;
	}
	public static string CleanMultipleDelimiters(this string sThis, char delimiter)
	{
		string t = sThis, d = string.Format("{0}{0}", delimiter);
		while (t.Contains(d))
			t = t.Replace(d, delimiter.ToString());
		return t;
	}
	public static string TruncateBetween(this string s, int indexStart, int indexEnd)
	{
		if (indexEnd < indexStart)
			throw new ArgumentException(string.Format(
				"Staring index ({0}) can't be bigger than ending index ({1}).", indexStart, indexEnd));
		if (indexEnd < s.Length)
		{
			Match m = rgxEndOfSentence.Match(s, indexStart);
			if (m.Success)
			{
				s = s.Substring(0, m.Index + 1);
			}
			else
			{
				if (s.Length > indexEnd)
					s = s.Substring(0, indexEnd);
			}
		}
		return s;
	}
	public static string TruncateAndClose(this string s, int indexStart, int indexEnd, string closingText, bool closeTags)
	{
		string t = s.TruncateBetween(indexStart, indexEnd);
		if (!t.Equals(s))
			t += closingText;
		if (closeTags)
			t = t.CloseOpenTags();
		return t;
	}
	public static string CloseOpenTags(this string text)
	{
		List<string> lstOpenTags = new List<string>();
		MatchCollection mclTags = rgxTag.Matches(text);
		int offset = 0;
		StringBuilder sbText = new StringBuilder(text);
		foreach (Match mTag in mclTags)
		{
			if (mTag.Groups[1].Value.Equals("/")) // closing?
			{
				bool open = false; // find out if it
				foreach (string openTag in lstOpenTags)
				{
					if (openTag.Equals(mTag.Groups[2].Value, StringComparison.CurrentCultureIgnoreCase))
						open = true; // .. had been opened previously
				}
				if (open) // if so
				{
					while (!lstOpenTags[lstOpenTags.Count - 1].Equals(mTag.Groups[2].Value))
					{ // make sure we close all open tags that miss their closing tag
						string s = string.Format("</{0}>", lstOpenTags[lstOpenTags.Count - 1]);
						sbText.Insert(mTag.Index + offset, s);
						offset += s.Length;
						lstOpenTags.RemoveAt(lstOpenTags.Count - 1);
					}
					lstOpenTags.RemoveAt(lstOpenTags.Count - 1);
				}
			}
			else
			{
				lstOpenTags.Add(mTag.Groups[2].Value);
			}
		}
		while (lstOpenTags.Count > 0)
		{
			string s = string.Format("</{0}>", lstOpenTags[lstOpenTags.Count - 1]);
			sbText.Append(s);
			lstOpenTags.RemoveAt(lstOpenTags.Count - 1);
		}
		return sbText.ToString();
	}
	public static string PickNext(this string This)
	{
		if (string.IsNullOrEmpty(This))
			return "a";

		StringBuilder sb = new StringBuilder();
		for (int i = This.Length - 1; i >= 0; --i)
		{
			Tuple<char, bool> nextChar = This[i].PickNext(i > 0);
			sb.Insert(0, nextChar.Item0);
			if (!nextChar.Item1)
			{
				sb.Insert(0, This.Substring(0, i));
				break;
			}
			else
			{
				if (i == 0)
					sb.Insert(0, "a");
			}
		}
		This = sb.ToString();

		return This;
	}
}
